; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=jump-threading < %s | FileCheck %s

%class.E = type { ptr, %class.C }
%class.C = type { %class.A }
%class.A = type { i32 }
%class.D = type { %class.F }
%class.F = type { %class.E }
%class.B = type { ptr }

@_ZTV1D = unnamed_addr constant [3 x ptr] [ptr null, ptr @_ZTI1D, ptr @_ZN1D7doApplyEv]
@_ZTI1D = external unnamed_addr constant { ptr, ptr, ptr }

define void @_ZN15EditCommandImpl5applyEv(ptr %this) uwtable align 2 {
; CHECK-LABEL: @_ZN15EditCommandImpl5applyEv(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[VTABLE:%.*]] = load ptr, ptr [[THIS:%.*]], align 8
; CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[VTABLE]], align 8
; CHECK-NEXT:    call void [[TMP0]](ptr [[THIS]])
; CHECK-NEXT:    ret void
;
entry:
  %vtable = load ptr, ptr %this, align 8
  %0 = load ptr, ptr %vtable, align 8
  call void %0(ptr %this)
  ret void
}

define void @_ZN1DC1Ev(ptr nocapture %this) unnamed_addr uwtable align 2 {
; CHECK-LABEL: @_ZN1DC1Ev(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    call void @_ZN24CompositeEditCommandImplC2Ev()
; CHECK-NEXT:    store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1D, i64 0, i64 2), ptr [[THIS:%.*]], align 8
; CHECK-NEXT:    ret void
;
entry:
  call void @_ZN24CompositeEditCommandImplC2Ev()
  store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1D, i64 0, i64 2), ptr %this, align 8
  ret void
}

define void @_ZN1DC2Ev(ptr nocapture %this) unnamed_addr uwtable align 2 {
; CHECK-LABEL: @_ZN1DC2Ev(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    call void @_ZN24CompositeEditCommandImplC2Ev()
; CHECK-NEXT:    store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1D, i64 0, i64 2), ptr [[THIS:%.*]], align 8
; CHECK-NEXT:    ret void
;
entry:
  call void @_ZN24CompositeEditCommandImplC2Ev()
  store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1D, i64 0, i64 2), ptr %this, align 8
  ret void
}

declare void @_ZN24CompositeEditCommandImplC2Ev() #1

define void @_ZN1D7doApplyEv(ptr nocapture %this) unnamed_addr nounwind readnone uwtable align 2 {
; CHECK-LABEL: @_ZN1D7doApplyEv(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret void
;
entry:
  ret void
}

define void @_Z3fn1v() uwtable personality ptr @__gxx_personality_v0 {
; CHECK-LABEL: @_Z3fn1v(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CALL:%.*]] = call noalias ptr @_Znwm()
; CHECK-NEXT:    invoke void @_ZN24CompositeEditCommandImplC2Ev()
; CHECK-NEXT:    to label [[_ZN1DC1EV_EXIT:%.*]] unwind label [[LPAD:%.*]]
; CHECK:       _ZN1DC1Ev.exit:
; CHECK-NEXT:    store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1D, i64 0, i64 2), ptr [[CALL]], align 8
; CHECK-NEXT:    [[_REF_I_I_I:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[_REF_I_I_I]], align 4
; CHECK-NEXT:    [[INC_I_I_I:%.*]] = add nsw i32 [[TMP0]], 1
; CHECK-NEXT:    store i32 [[INC_I_I_I]], ptr [[_REF_I_I_I]], align 4
; CHECK-NEXT:    invoke void @_ZN1D7doApplyEv(ptr [[CALL]])
; CHECK-NEXT:    to label [[_ZN15EDITCOMMANDIMPL5APPLYEV_EXIT:%.*]] unwind label [[LPAD1:%.*]]
; CHECK:       _ZN15EditCommandImpl5applyEv.exit:
; CHECK-NEXT:    invoke void @_ZN1D16deleteKeyPressedEv()
; CHECK-NEXT:    to label [[INVOKE_CONT7:%.*]] unwind label [[LPAD1]]
; CHECK:       invoke.cont7:
; CHECK-NEXT:    ret void
; CHECK:       lpad:
; CHECK-NEXT:    [[TMP1:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT:    cleanup
; CHECK-NEXT:    call void @_ZdlPv()
; CHECK-NEXT:    unreachable
; CHECK:       lpad1:
; CHECK-NEXT:    [[TMP2:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT:    cleanup
; CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[_REF_I_I_I]], align 4
; CHECK-NEXT:    [[TOBOOL_I_I_I:%.*]] = icmp eq i32 [[TMP3]], 0
; CHECK-NEXT:    br i1 [[TOBOOL_I_I_I]], label [[_ZN1BI1DED1EV_EXIT:%.*]], label [[DELETE_NOTNULL_I_I_I:%.*]]
; CHECK:       delete.notnull.i.i.i:
; CHECK-NEXT:    call void @_ZdlPv()
; CHECK-NEXT:    unreachable
; CHECK:       _ZN1BI1DED1Ev.exit:
; CHECK-NEXT:    resume { ptr, i32 } undef
; CHECK:       terminate.lpad:
; CHECK-NEXT:    [[TMP4:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT:    catch ptr null
; CHECK-NEXT:    unreachable
;
entry:
  %call = call noalias ptr @_Znwm() #8
  invoke void @_ZN24CompositeEditCommandImplC2Ev()
  to label %_ZN1DC1Ev.exit unwind label %lpad

_ZN1DC1Ev.exit:                                   ; preds = %entry
  store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1D, i64 0, i64 2), ptr %call, align 8
  %_ref.i.i.i = getelementptr inbounds i8, ptr %call, i64 8
  %0 = load i32, ptr %_ref.i.i.i, align 4
  %inc.i.i.i = add nsw i32 %0, 1
  store i32 %inc.i.i.i, ptr %_ref.i.i.i, align 4
  invoke void @_ZN1D7doApplyEv(ptr %call)
  to label %_ZN15EditCommandImpl5applyEv.exit unwind label %lpad1

_ZN15EditCommandImpl5applyEv.exit:                ; preds = %_ZN1DC1Ev.exit
  invoke void @_ZN1D16deleteKeyPressedEv()
  to label %invoke.cont7 unwind label %lpad1

invoke.cont7:                                     ; preds = %_ZN15EditCommandImpl5applyEv.exit
  ret void

lpad:                                             ; preds = %entry
  %1 = landingpad { ptr, i32 }
  cleanup
  call void @_ZdlPv() #9
  unreachable

lpad1:                                            ; preds = %_ZN1DC1Ev.exit, %_ZN15EditCommandImpl5applyEv.exit
  %2 = landingpad { ptr, i32 }
  cleanup
  %3 = load i32, ptr %_ref.i.i.i, align 4
  %tobool.i.i.i = icmp eq i32 %3, 0
  br i1 %tobool.i.i.i, label %_ZN1BI1DED1Ev.exit, label %if.then.i.i.i

if.then.i.i.i:                                    ; preds = %lpad1
  br i1 undef, label %_ZN1BI1DED1Ev.exit, label %delete.notnull.i.i.i

delete.notnull.i.i.i:                             ; preds = %if.then.i.i.i
  call void @_ZdlPv() #9
  unreachable

_ZN1BI1DED1Ev.exit:                               ; preds = %lpad1, %if.then.i.i.i
  resume { ptr, i32 } undef

terminate.lpad:                                   ; No predecessors!
  %4 = landingpad { ptr, i32 }
  catch ptr null
  unreachable
}

define void @_ZN1BI1DEC1EPS0_(ptr nocapture %this, ptr %p1) unnamed_addr uwtable align 2 {
; CHECK-LABEL: @_ZN1BI1DEC1EPS0_(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    store ptr [[P1:%.*]], ptr [[THIS:%.*]], align 8
; CHECK-NEXT:    [[_REF_I_I:%.*]] = getelementptr inbounds [[CLASS_D:%.*]], ptr [[P1]], i64 0, i32 0, i32 0, i32 1, i32 0, i32 0
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[_REF_I_I]], align 4
; CHECK-NEXT:    [[INC_I_I:%.*]] = add nsw i32 [[TMP0]], 1
; CHECK-NEXT:    store i32 [[INC_I_I]], ptr [[_REF_I_I]], align 4
; CHECK-NEXT:    ret void
;
entry:
  store ptr %p1, ptr %this, align 8
  %_ref.i.i = getelementptr inbounds %class.D, ptr %p1, i64 0, i32 0, i32 0, i32 1, i32 0, i32 0
  %0 = load i32, ptr %_ref.i.i, align 4
  %inc.i.i = add nsw i32 %0, 1
  store i32 %inc.i.i, ptr %_ref.i.i, align 4
  ret void
}

declare noalias ptr @_Znwm()

declare i32 @__gxx_personality_v0(...)

declare void @_ZdlPv()

define ptr @_ZN1BI1DEptEv(ptr nocapture readonly %this) nounwind readonly uwtable align 2 {
; CHECK-LABEL: @_ZN1BI1DEptEv(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[THIS:%.*]], align 8
; CHECK-NEXT:    ret ptr [[TMP0]]
;
entry:
  %0 = load ptr, ptr %this, align 8
  ret ptr %0
}

declare void @_ZN1D16deleteKeyPressedEv()

define void @_ZN1BI1DED1Ev(ptr nocapture readonly %this) unnamed_addr uwtable align 2 {
; CHECK-LABEL: @_ZN1BI1DED1Ev(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[THIS:%.*]], align 8
; CHECK-NEXT:    [[_REF_I_I:%.*]] = getelementptr inbounds [[CLASS_D:%.*]], ptr [[TMP0]], i64 0, i32 0, i32 0, i32 1, i32 0, i32 0
; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[_REF_I_I]], align 4
; CHECK-NEXT:    [[TOBOOL_I_I:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK-NEXT:    br i1 [[TOBOOL_I_I]], label [[_ZN1BI1DED2EV_EXIT:%.*]], label [[DELETE_NOTNULL_I_I:%.*]]
; CHECK:       delete.notnull.i.i:
; CHECK-NEXT:    call void @_ZdlPv()
; CHECK-NEXT:    unreachable
; CHECK:       _ZN1BI1DED2Ev.exit:
; CHECK-NEXT:    ret void
;
entry:
  %0 = load ptr, ptr %this, align 8
  %_ref.i.i = getelementptr inbounds %class.D, ptr %0, i64 0, i32 0, i32 0, i32 1, i32 0, i32 0
  %1 = load i32, ptr %_ref.i.i, align 4
  %tobool.i.i = icmp eq i32 %1, 0
  br i1 %tobool.i.i, label %_ZN1BI1DED2Ev.exit, label %if.then.i.i

if.then.i.i:                                      ; preds = %entry
  br i1 undef, label %_ZN1BI1DED2Ev.exit, label %delete.notnull.i.i

delete.notnull.i.i:                               ; preds = %if.then.i.i
  call void @_ZdlPv() #9
  unreachable

_ZN1BI1DED2Ev.exit:                               ; preds = %entry, %if.then.i.i
  ret void
}

declare hidden void @__clang_call_terminate()

define void @_ZN1BI1DED2Ev(ptr nocapture readonly %this) unnamed_addr uwtable align 2 {
; CHECK-LABEL: @_ZN1BI1DED2Ev(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[THIS:%.*]], align 8
; CHECK-NEXT:    [[_REF_I:%.*]] = getelementptr inbounds [[CLASS_D:%.*]], ptr [[TMP0]], i64 0, i32 0, i32 0, i32 1, i32 0, i32 0
; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[_REF_I]], align 4
; CHECK-NEXT:    [[TOBOOL_I:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK-NEXT:    br i1 [[TOBOOL_I]], label [[_ZN1AI1CE5DEREFEV_EXIT:%.*]], label [[DELETE_NOTNULL_I:%.*]]
; CHECK:       delete.notnull.i:
; CHECK-NEXT:    call void @_ZdlPv()
; CHECK-NEXT:    unreachable
; CHECK:       _ZN1AI1CE5derefEv.exit:
; CHECK-NEXT:    ret void
;
entry:
  %0 = load ptr, ptr %this, align 8
  %_ref.i = getelementptr inbounds %class.D, ptr %0, i64 0, i32 0, i32 0, i32 1, i32 0, i32 0
  %1 = load i32, ptr %_ref.i, align 4
  %tobool.i = icmp eq i32 %1, 0
  br i1 %tobool.i, label %_ZN1AI1CE5derefEv.exit, label %if.then.i

if.then.i:                                        ; preds = %entry
  br i1 undef, label %_ZN1AI1CE5derefEv.exit, label %delete.notnull.i

delete.notnull.i:                                 ; preds = %if.then.i
  call void @_ZdlPv() #9
  unreachable

_ZN1AI1CE5derefEv.exit:                           ; preds = %entry, %if.then.i
  ret void
}

define void @_ZN1AI1CE5derefEv(ptr nocapture readonly %this) nounwind uwtable align 2 {
; CHECK-LABEL: @_ZN1AI1CE5derefEv(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[THIS:%.*]], align 4
; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[DELETE_NOTNULL:%.*]]
; CHECK:       delete.notnull:
; CHECK-NEXT:    call void @_ZdlPv()
; CHECK-NEXT:    unreachable
; CHECK:       if.end:
; CHECK-NEXT:    ret void
;
entry:
  %0 = load i32, ptr %this, align 4
  %tobool = icmp eq i32 %0, 0
  br i1 %tobool, label %if.end, label %if.then

if.then:                                          ; preds = %entry
  br i1 undef, label %if.end, label %delete.notnull

delete.notnull:                                   ; preds = %if.then
  call void @_ZdlPv() #9
  unreachable

if.end:                                           ; preds = %entry, %if.then
  ret void
}

define void @_ZN1BI1DEC2EPS0_(ptr nocapture %this, ptr %p1) unnamed_addr uwtable align 2 {
; CHECK-LABEL: @_ZN1BI1DEC2EPS0_(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    store ptr [[P1:%.*]], ptr [[THIS:%.*]], align 8
; CHECK-NEXT:    [[_REF_I:%.*]] = getelementptr inbounds [[CLASS_D:%.*]], ptr [[P1]], i64 0, i32 0, i32 0, i32 1, i32 0, i32 0
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[_REF_I]], align 4
; CHECK-NEXT:    [[INC_I:%.*]] = add nsw i32 [[TMP0]], 1
; CHECK-NEXT:    store i32 [[INC_I]], ptr [[_REF_I]], align 4
; CHECK-NEXT:    ret void
;
entry:
  store ptr %p1, ptr %this, align 8
  %_ref.i = getelementptr inbounds %class.D, ptr %p1, i64 0, i32 0, i32 0, i32 1, i32 0, i32 0
  %0 = load i32, ptr %_ref.i, align 4
  %inc.i = add nsw i32 %0, 1
  store i32 %inc.i, ptr %_ref.i, align 4
  ret void
}

define void @_ZN1AI1CE3refEv(ptr nocapture %this) nounwind uwtable align 2 {
; CHECK-LABEL: @_ZN1AI1CE3refEv(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[THIS:%.*]], align 4
; CHECK-NEXT:    [[INC:%.*]] = add nsw i32 [[TMP0]], 1
; CHECK-NEXT:    store i32 [[INC]], ptr [[THIS]], align 4
; CHECK-NEXT:    ret void
;
entry:
  %0 = load i32, ptr %this, align 4
  %inc = add nsw i32 %0, 1
  store i32 %inc, ptr %this, align 4
  ret void
}
